From 729ba8111a5eac146b833c7f5f943c9df583039d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 14 Sep 2021 07:48:49 -0400 Subject: [PATCH] Add code to load jpegs This lets us avoid gdk-pixbuf for loading textures from the common image formats. As a consequence, we are now linking against libjpeg. --- gdk/loaders/gdkjpeg.c | 146 +++++++++++++++++++++++++++++++++++ gdk/loaders/gdkjpegprivate.h | 29 +++++++ gdk/meson.build | 2 + meson.build | 3 + 4 files changed, 180 insertions(+) create mode 100644 gdk/loaders/gdkjpeg.c create mode 100644 gdk/loaders/gdkjpegprivate.h diff --git a/gdk/loaders/gdkjpeg.c b/gdk/loaders/gdkjpeg.c new file mode 100644 index 0000000000..74a1c9623a --- /dev/null +++ b/gdk/loaders/gdkjpeg.c @@ -0,0 +1,146 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkjpegprivate.h" + +#include "gdktexture.h" +#include "gdkmemorytextureprivate.h" +#include +#include +#include + +/* {{{ Error handling */ + +/* No sigsetjmp on Windows */ +#ifndef HAVE_SIGSETJMP +#define sigjmp_buf jmp_buf +#define sigsetjmp(jb, x) setjmp(jb) +#define siglongjmp longjmp +#endif + +struct error_handler_data { + struct jpeg_error_mgr pub; + sigjmp_buf setjmp_buffer; + GError **error; +}; + +static void +fatal_error_handler (j_common_ptr cinfo) +{ + struct error_handler_data *errmgr; + char buffer[JMSG_LENGTH_MAX]; + + errmgr = (struct error_handler_data *) cinfo->err; + + cinfo->err->format_message (cinfo, buffer); + + if (errmgr->error && *errmgr->error == NULL) + g_set_error (errmgr->error, + GDK_TEXTURE_ERROR, + cinfo->err->msg_code == JERR_OUT_OF_MEMORY + ? GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY + : GDK_TEXTURE_ERROR_CORRUPT_IMAGE, + "Error interpreting JPEG image file (%s)", buffer); + + siglongjmp (errmgr->setjmp_buffer, 1); + + g_assert_not_reached (); +} + +static void +output_message_handler (j_common_ptr cinfo) +{ + /* do nothing */ +} + +/* }}} */ + /* {{{ Public API */ + +GdkTexture * +gdk_load_jpeg (GBytes *input_bytes, + GError **error) +{ + struct jpeg_decompress_struct info; + struct error_handler_data jerr; + struct jpeg_error_mgr err; + int width, height; + int size; + unsigned char *data; + unsigned char *row[1]; + GBytes *bytes; + GdkTexture *texture; + + info.err = jpeg_std_error (&jerr.pub); + jerr.pub.error_exit = fatal_error_handler; + jerr.pub.output_message = output_message_handler; + jerr.error = error; + + if (sigsetjmp (jerr.setjmp_buffer, 1)) + { + jpeg_destroy_decompress (&info); + return NULL; + } + + info.err = jpeg_std_error (&err); + jpeg_create_decompress (&info); + + jpeg_mem_src (&info, + g_bytes_get_data (input_bytes, NULL), + g_bytes_get_size (input_bytes)); + + jpeg_read_header (&info, TRUE); + jpeg_start_decompress (&info); + + width = info.output_width; + height = info.output_height; + + size = width * height * 3; + data = g_try_malloc_n (width * 3, height); + if (!data) + { + g_set_error_literal (error, + GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY, + "Not enough memory to load jpeg"); + jpeg_destroy_decompress (&info); + return NULL; + } + + while (info.output_scanline < info.output_height) + { + row[0] = (unsigned char *)(&data[3 *info.output_width * info.output_scanline]); + jpeg_read_scanlines (&info, row, 1); + } + + jpeg_finish_decompress (&info); + jpeg_destroy_decompress (&info); + + bytes = g_bytes_new_take (data, size); + + texture = gdk_memory_texture_new (width, height, + GDK_MEMORY_R8G8B8, + bytes, width * 3); + + g_bytes_unref (bytes); + + return texture; +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ diff --git a/gdk/loaders/gdkjpegprivate.h b/gdk/loaders/gdkjpegprivate.h new file mode 100644 index 0000000000..a8e6bd8a82 --- /dev/null +++ b/gdk/loaders/gdkjpegprivate.h @@ -0,0 +1,29 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_JPEG_PRIVATE_H__ +#define __GDK_JPEG_PRIVATE_H__ + +#include "gdkmemorytexture.h" +#include + +#define JPEG_SIGNATURE "\xff\xd8" + +GdkTexture *gdk_load_jpeg (GBytes *bytes, + GError **error); + +#endif diff --git a/gdk/meson.build b/gdk/meson.build index 6ef0ec01fb..06905233f8 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -53,6 +53,7 @@ gdk_public_sources = files([ 'gdkdragsurface.c', 'loaders/gdkpng.c', 'loaders/gdktiff.c', + 'loaders/gdkjpeg.c', ]) gdk_public_headers = files([ @@ -205,6 +206,7 @@ gdk_deps = [ vulkan_dep, png_dep, tiff_dep, + jpeg_dep, ] if profiler_enabled diff --git a/meson.build b/meson.build index 4aa622bbaf..e85daf88f5 100644 --- a/meson.build +++ b/meson.build @@ -406,6 +406,9 @@ png_dep = dependency('libpng', tiff_dep = dependency('libtiff-4', fallback: ['libtiff', 'libtiff4_dep'], required: true) +jpeg_dep = dependency('libjpeg', + fallback: ['libjpeg-turbo', 'jpeg_dep'], + required: true) epoxy_dep = dependency('epoxy', version: epoxy_req, fallback: ['libepoxy', 'libepoxy_dep']) -- 2.30.2